#include "CHuGlobalMercator.h"
#include <qDebug>
CHuGlobalMercator::CHuGlobalMercator(int tileSize)
{
    //"Initialize the TMS Global Mercator pyramid"
    // self.tileSize = tileSize
    // self.initialResolution = 2 * math.pi * 6378137 / self.tileSize
    // # 156543.03392804062 for tileSize 256 pixels
    // self.originShift = 2 * math.pi * 6378137 / 2.0
    // # 20037508.342789244
    m_pi = 3.141592653589793;
    m_tileSize = tileSize;
    m_initialResolution = 2 * m_pi * 6378137 / m_tileSize;
    m_originShift = 2 * m_pi * 6378137 / 2.0;
}
///
//def LatLonToMeters(self, lat, lon ):
//"Converts given lat/lon in WGS84 Datum to XY in Spherical Mercator EPSG:3857"
//
// mx = lon * self.originShift / 180.0
// my = math.log( math.tan((90 + lat) * math.pi / 360.0 )) / (math.pi / 180.0)
//
// my = my * self.originShift / 180.0
// return mx, my
void CHuGlobalMercator::LatLonToMeters(double lon, double lat,double* mxy)
{
    mxy[0] = lon * m_originShift / 180.0;
    mxy[1] = log( tan((90 + lat) * m_pi / 360.0 )) / (m_pi / 180.0);

    mxy[1] = mxy[1] * m_originShift / 180.0;
}

// def MetersToLatLon(self, mx, my ):
//"Converts XY point from Spherical Mercator EPSG:3857 to lat/lon in WGS84 Datum"
//
// lon = (mx / self.originShift) * 180.0
// lat = (my / self.originShift) * 180.0
//
// lat = 180 / math.pi * (2 * math.atan( math.exp( lat * math.pi / 180.0)) - math.pi / 2.0)
// return lat, lon
void CHuGlobalMercator::MetersToLatLon(double mx, double my, double* LatLon)
{
    LatLon[1] = (mx / m_originShift) * 180.0;
    LatLon[0] = (my / m_originShift) * 180.0;

    LatLon[0] = 180 / m_pi * (2 * atan( exp( LatLon[0] * m_pi / 180.0)) - m_pi / 2.0);
}

// def PixelsToMeters(self, px, py, zoom):
//"Converts pixel coordinates in given zoom level of pyramid to EPSG:3857"
//
// res = self.Resolution( zoom )
// mx = px * res - self.originShift
// my = py * res - self.originShift
// return mx, my
void CHuGlobalMercator::PixelsToMeters(double px, double py, int zoom, double* mxy)
{
    double res = Resolution( zoom );
    mxy[0] = px * res - m_originShift;
    mxy[1] = py * res - m_originShift;
}

// def MetersToPixels(self, mx, my, zoom):
//"Converts EPSG:3857 to pyramid pixel coordinates in given zoom level"
//
// res = self.Resolution( zoom )
// px = (mx + self.originShift) / res
// py = (my + self.originShift) / res
// return px, py
void CHuGlobalMercator::MetersToPixels(double mx, double my, int zoom, double* pxy)
{
    double res = Resolution( zoom );
    pxy[0] = (mx + m_originShift) / res;
    pxy[1] = (my + m_originShift) / res;
//    pxy[0] = (fabs(mx) + m_originShift) / res;
    //    pxy[1] = (fabs(my) + m_originShift) / res;
}

void CHuGlobalMercator::MetersToPixelclip(double mx, double my, int tx, int ty, int zoom, double *pxy)
{
    double res = Resolution( zoom );

    pxy[0] = ((mx + m_originShift) / res) - tx*m_tileSize ;
    pxy[1] = ((my + m_originShift) / res)- ty*m_tileSize;

}

// def PixelsToTile(self, px, py):
//"Returns a tile covering region in given pixel coordinates"
//
// tx = int( math.ceil( px / float(self.tileSize) ) - 1 )
// ty = int( math.ceil( py / float(self.tileSize) ) - 1 )
// return tx, ty
void CHuGlobalMercator::PixelsToTile(double px, double py, int* txy)
{
    txy[0] = int( ceil( px / float(m_tileSize) ) - 1 );
    txy[1] = int( ceil( py / float(m_tileSize) ) - 1 );
}

// def PixelsToRaster(self, px, py, zoom):
//"Move the origin of pixel coordinates to top-left corner"
//
// mapSize = self.tileSize << zoom
// return px, mapSize - py

// def MetersToTile(self, mx, my, zoom):
//"Returns tile for given mercator coordinates"
//
// px, py = self.MetersToPixels( mx, my, zoom)
// return self.PixelsToTile( px, py)
void CHuGlobalMercator::MetersToTile(double mx, double my, int zoom, int* txy)
{
    double res = Resolution( zoom );
    double px = (mx + m_originShift) / res;
    double py = (my + m_originShift) / res;

    txy[0] = int( ceil( px / float(m_tileSize) ) - 1 );
    txy[1] = int( ceil( py / float(m_tileSize) ) - 1 );
}
// y轴从上到下递增的情况
void CHuGlobalMercator::MetersToTile2(double mx, double my, int zoom, int* txy)
{
    double res = Resolution( zoom );
    double px = (mx + m_originShift) / res;
    double py = (m_originShift - my) / res;//注意该处是减号

    txy[0] = int( ceil( px / float(m_tileSize) ) - 1 );
    txy[1] = int( ceil( py / float(m_tileSize) ) - 1 );
}

// def TileBounds(self, tx, ty, zoom):
//"Returns bounds of the given tile in EPSG:3857 coordinates"
//
// minx, miny = self.PixelsToMeters( tx*self.tileSize, ty*self.tileSize, zoom )
// maxx, maxy = self.PixelsToMeters( (tx+1)*self.tileSize, (ty+1)*self.tileSize, zoom )
// return ( minx, miny, maxx, maxy )
void CHuGlobalMercator::TileBounds(int tx, int ty,int zoom, double* bound4)
{
    double res = Resolution( zoom );
    bound4[0] = tx * m_tileSize * res - m_originShift;
    bound4[1] = ty * m_tileSize * res - m_originShift;
    bound4[2] = (tx+1) * m_tileSize * res - m_originShift;
    bound4[3] = (ty+1) * m_tileSize * res - m_originShift;
}
// y轴从上到下递增的情况
void CHuGlobalMercator::TileBounds2(int tx, int ty,int zoom, double* bound4)
{
    double res = Resolution( zoom );
    bound4[0] = tx * m_tileSize * res - m_originShift;
    bound4[1] = m_originShift - ty * m_tileSize * res;//
    bound4[2] = (tx+1) * m_tileSize * res - m_originShift;
    bound4[3] = m_originShift - (ty+1) * m_tileSize * res;//
}

// def TileLatLonBounds(self, tx, ty, zoom ):
//"Returns bounds of the given tile in latitude/longitude using WGS84 datum"
//
// bounds = self.TileBounds( tx, ty, zoom)
// minLat, minLon = self.MetersToLatLon(bounds[0], bounds[1])
// maxLat, maxLon = self.MetersToLatLon(bounds[2], bounds[3])
//
// return ( minLat, minLon, maxLat, maxLon )
void CHuGlobalMercator::TileLatLonBounds(int tx, int ty,int zoom, double* LatLonbound4)
{
    double res = Resolution( zoom );
    double minx = tx * m_tileSize * res - m_originShift;
    double miny = ty * m_tileSize * res - m_originShift;
    double maxx = (tx+1) * m_tileSize * res - m_originShift;
    double maxy = (ty+1) * m_tileSize * res - m_originShift;

    LatLonbound4[1] = (minx / m_originShift) * 180.0;
    LatLonbound4[0] = (miny / m_originShift) * 180.0;
    LatLonbound4[0] = 180 / m_pi * (2 * atan( exp( LatLonbound4[0] * m_pi / 180.0)) - m_pi / 2.0);

    LatLonbound4[3] = (maxx / m_originShift) * 180.0;
    LatLonbound4[2] = (maxy / m_originShift) * 180.0;
    LatLonbound4[2] = 180 / m_pi * (2 * atan( exp( LatLonbound4[2] * m_pi / 180.0)) - m_pi / 2.0);
}

void CHuGlobalMercator::PixelsToRaster(double px, double py, int zoom, int *bound4)
{
    int mapSize = this->m_tileSize << zoom;
    bound4[0] = px;
    bound4[1] = mapSize - py;

}


//
// def Resolution(self, zoom ):
//"Resolution (meters/pixel) for given zoom level (measured at Equator)"
//
//# return (2 * math.pi * 6378137) / (self.tileSize * 2**zoom)
// return self.initialResolution / (2**zoom)
double CHuGlobalMercator::Resolution(int zoom)
{
    return m_initialResolution / pow(2,(double)zoom);
}
///
// def ZoomForPixelSize(self, pixelSize ):
//"Maximal scaledown zoom of the pyramid closest to the pixelSize."
//
// for i in range(MAXZOOMLEVEL):
//if pixelSize > self.Resolution(i):
//if i!=0:
//return i-1
//else:
//return 0 # We don't want to scale up
int CHuGlobalMercator::ZoomForPixelSize(double pixelSize)
{
    for (int i=0; i<32; i++)
    {
        if (pixelSize > Resolution(i))
        {
            if (i != 0)
            {
                return i-1;
            }
            else
            {
                return 0;
            }
        }
    }
}

// def GoogleTile(self, tx, ty, zoom):
//"Converts TMS tile coordinates to Google Tile coordinates"
//
//# coordinate origin is moved from bottom-left to top-left corner of the extent
// return tx, (2**zoom - 1) - ty
void CHuGlobalMercator::GoogleTile(int tx, int ty,int zoom, int* txy)
{
    txy[0] = tx;
    txy[1] = (pow(2,(double)zoom) - 1) - ty;
}
//度转为弧度
double CHuGlobalMercator::DegreesToRadians(double fRad)
{
    double  Rad_to_deg = 45.0 / atan(1.0);
    double fAngle = fRad*Rad_to_deg;
    return fAngle;

}
